﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Collections;
using System.Threading;

namespace Framework.ObjectPool
{
    public class Pool
    {
        // 对象集合
        private List<IPoolInstance> collection = null;
        // 最大容量
        private int maxPoolCount = 100;
        // 最小容量
        private int minPoolCount = 30;
        // 申请对象延时(秒)
        private int applyInstanceInterval = 2;
        // 清理对象池对象的间隔时间(秒)
        private int releaseIntervalTime = 60 * 60;
        // 定时清理对象池对象
        private Timer timer = null;
        // 对象构造方法
        private Func<IPoolInstance> generator = null;
        // 同步锁
        private object lockObj = new object();

        public Pool(int maxPoolCount, int minPoolCount, int releaseIntervalTime, Func<IPoolInstance> generator)
        {
            this.releaseIntervalTime = releaseIntervalTime;
            this.maxPoolCount = maxPoolCount;
            this.minPoolCount = minPoolCount;
            this.generator = generator;
            this.collection = new List<IPoolInstance>();
            for (int i = 0; i < this.minPoolCount; i++)
            {
                IPoolInstance instance = generator();
                instance.Status = PoolInstanceStatus.Free;
                this.collection.Add(instance);
            }
            AutoReleaseInstance();
        }

        public Pool(Func<IPoolInstance> generator)
        {
            this.generator = generator;
            this.collection = new List<IPoolInstance>();
            for (int i = 0; i < this.minPoolCount; i++)
            {
                IPoolInstance instance = generator();
                instance.Status = PoolInstanceStatus.Free;
                this.collection.Add(instance);
            }
            AutoReleaseInstance();
        }

        /// <summary>
        /// 获取一个对象实例
        /// </summary>
        /// <returns>返回内部实际对象，若返回null则线程池已满</returns>
        public IPoolInstance GetInstance()
        {
            IPoolInstance instance = null;
            lock (lockObj)
            {
                foreach (IPoolInstance item in this.collection)
                {
                    if (item != null && item.Status == PoolInstanceStatus.Free)
                    {
                        item.Status = PoolInstanceStatus.Busy;
                        instance = item;
                        break;
                    }
                }

                if (instance == null && this.collection.Count < this.maxPoolCount)
                {
                    instance = this.generator();
                    instance.Status = PoolInstanceStatus.Busy;
                    this.collection.Add(instance);
                }
            }

            if (instance == null)
            {
                Thread.Sleep(applyInstanceInterval * 1000);
                instance = GetInstance();
            }
            return instance;
        }

        /// <summary>
        /// 将对象池中指定的对象重置并设置为空闲状态
        /// </summary>
        public void Return(IPoolInstance obj) 
        {
            obj.Status = PoolInstanceStatus.Free;
        }

        /// <summary>
        /// 释放对象
        /// </summary>
        /// <param name="obj"></param>
        public void ReleaseInstance(IPoolInstance obj)
        {
            lock (lockObj)
            {
                this.collection.Remove(obj);
            }
        }

        /// <summary>
        /// 手动清理对象池
        /// </summary>
        public void ReleaseInstance()
        {
            if (this.collection.Count(p => p.Status == PoolInstanceStatus.Free) > this.minPoolCount)
            {
                lock (lockObj)
                {
                    int count = this.collection.Count(p => p.Status == PoolInstanceStatus.Free) - this.minPoolCount;
                    if (count > 0)
                    {
                        var temp = this.collection.Where(p => p.Status == PoolInstanceStatus.Free).Take(count);
                        foreach (var tempOne in temp)
                        {
                            tempOne.Status = PoolInstanceStatus.Invalid;
                        }
                        this.collection.RemoveAll(p=>p.Status == PoolInstanceStatus.Invalid);
                    }
                }
            }
        }

        /// <summary>
        /// 自动清理对象池
        /// </summary>
        private void AutoReleaseInstance()
        {
            timer = new Timer(p => { ReleaseInstance(); }, null, this.releaseIntervalTime * 1000, this.releaseIntervalTime * 1000);
        }

    }
}
